
import java.awt.Color;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;

import drawing.AlgebraicLine;
import excaptions.AandBZeroException;

import ownclasses.Eigensolver2x2;
import ownclasses.Eigensolver2x2.EigenPair;

import ij.IJ;
import ij.ImagePlus;
import ij.plugin.filter.PlugInFilter;
import ij.process.ByteProcessor;
import ij.process.ImageProcessor;

public class LabSession2_Ass2 implements PlugInFilter {
	
	String imageTitle = "findLine";
	
	public int setup(String arg, ImagePlus im) {
		return DOES_8C;
	}
	
	

	public void run(ImageProcessor ip) {
		
		int M = ip.getWidth();
		int N = ip.getHeight();
		
	   	
	   	ImageProcessor ip2 = new ByteProcessor(M, N);
	   	//bp.autoThreshold();
	   	ip2.invert();
		
		Point2D[] allPoints = collectAllPoints(ip, M, N);
		
		IJ.log("Number of detected Points: " + allPoints.length);
		IJ.log("");
	   	
		if(allPoints.length >= 2){
			double [] matA = computeMatrixA(allPoints);
			
			
				IJ.log("alpha: " + matA[0]);
				IJ.log("beta: " + matA[1]);
				IJ.log("gamma: " + matA[3]);
			
			
			EigenPair[] ep = Eigensolver2x2.realEigenValues2x2(matA[0], matA[1], matA[2], matA[3]);
			
			//pick the eigenvector with smaller eigenvalue
			int eigenpairIndex = 0;
			if(ep[1].getEigenvalue() < ep[0].getEigenvalue()){
				eigenpairIndex = 1;
			}
			
			double a = ep[eigenpairIndex].getEigenvector()[0];
			double b = ep[eigenpairIndex].getEigenvector()[1];
			//double a = ep[1].getEigenvector()[0];
			//double b = ep[1].getEigenvector()[1];
			int[] xSumYSum = getXSummGetYSumm(allPoints);
			//double c = -(a+b);
			double c = -xSumYSum[0]*a - xSumYSum[1]*b;
			
			// output in text form
			IJ.log("----------------------------");
			IJ.log("Eigenvector A: " + a);
			IJ.log("Eigenvector B: " + b);
			IJ.log("C " + c);
			IJ.log("----------------------------");
			
			AlgebraicLine line;
			try {
				line = new AlgebraicLine(a, b, c);
				line.draw(ip, Color.red);
			} catch (AandBZeroException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			//.drawElegant(ip);
			//line.drawBruteForce(ip);
		}
		
		// display the new image
		(new ImagePlus(imageTitle, ip)).show();
	}
	
	private int[] getXSummGetYSumm(Point2D[] allPoints) {
		int[] xSumYSum = new int[2];
		for (int i = 0; i < allPoints.length; i++) {
			xSumYSum[0] += allPoints[i].getX();
			xSumYSum[1] += allPoints[i].getY();
		}
		return xSumYSum;
	}



	private double[] computeMatrixA(Point2D[] allPoints) {
		
		int xsumm = 0;
		int xPowSumm = 0;
		int ysumm = 0;
		int yPowSumm = 0;
		int xySumm = 0;
		
		int n = allPoints.length;
		double x = 0;
		double y = 0;
		for (int i = 0; i < n; i++) {
			x = allPoints[i].getX();
			y = allPoints[i].getY();
			xsumm += x;
			ysumm += y;
			xySumm += x*y;
			xPowSumm += x*x;
			yPowSumm += y*y;
		}
		double factor = 1.0/n;

		IJ.log("");
		IJ.log("xsumm: " + xsumm);
		IJ.log("ysumm: " + ysumm);
		IJ.log("xySumm: " + xySumm);
		IJ.log("xPowSumm: " + xPowSumm);
		IJ.log("yPowSumm: " + yPowSumm);
		IJ.log("factor: " + factor);
		IJ.log("");
		IJ.log("    ");
		
		double xBar = factor * xsumm;
		double yBar = factor * ysumm;
		double xyBar = factor * xySumm;
		double xxBar = factor * xPowSumm;
		double yyBar = factor * yPowSumm;
		
		double alpha = xxBar - xBar*xBar;
		double beta = xyBar - xBar*yBar;
		double gamma = yyBar - yBar*yBar;
		
		
		return new double[]{alpha, beta, beta, gamma};
	}



	Point2D[] collectAllPoints(ImageProcessor ip, int width, int height){
		List<Point2D> plist = new ArrayList<Point2D>();
		
		for (int u = 0; u < width; u++) {
			for (int v = 0; v < height; v++) {
				int p = ip.getPixel(u,v);
				
				if(p == 0){
					plist.add(new Point(u,v));
				}
			}
		}
		return plist.toArray(new Point2D[0]);
	}

}
